package com.ccp.dev.workflow.bpmutil;

import com.ccp.dev.core.basic.table.ColumnModel;
import com.ccp.dev.core.basic.table.TableModel;
import com.ccp.dev.core.basic.util.ContextUtil;
import com.ccp.dev.core.basic.util.UUIDUtils;
import com.ccp.dev.core.util.AppUtil;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.form.consts.FormConstants;
import com.ccp.dev.form.model.*;
import com.ccp.dev.form.service.FormRightsService;
import com.ccp.dev.form.util.FormUtil;
import com.ccp.dev.form.util.PlatformType;
import com.ccp.dev.system.model.SysUser;
import com.ccp.dev.workflow.model.Identity;
import com.ccp.dev.workflow.service.IdentityService;
import com.ccp.dev.workflow.model.bpm.SqlModel;
import com.ccp.dev.workflow.service.FormHandlerService;
import net.sf.json.JSONArray;
import net.sf.json.JSONNull;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import java.util.*;

/**
 * 将json数据转换为FormData对象数据
 *
 * @author zks
 * @version 2019-07-24
 */
public class FormDataUtil {

    /**
     * 传入BpmFormData对象，解析成sqlmodel列表数据。
     *
     * @param formData
     * @param procDefId
     * @param nodeId
     * @return
     * @throws Exception
     */
    public static List<SqlModel> parseSql(FormData formData, String procDefId, String nodeId) throws Exception {
        PkValue pkValue = formData.getPkValue();
        boolean isAdd = pkValue.getIsAdd();
        List<SqlModel> list = new ArrayList<>();
        FormTable mainTable = formData.getFormTable();
        Map<String, FormTable> subTableMap = convertTableMap(mainTable.getSubTableList());
        if (isAdd) {
            SqlModel sqlModel = getInsert(mainTable, formData.getMainFields());
            sqlModel.setPk(pkValue.getValue().toString());
            sqlModel.setFormTable(mainTable);
            list.add(sqlModel);
            //插入子表数据
            for (SubTable subTable : formData.getSubTableList()) {
                String tableName = subTable.getTableName().toLowerCase();
                FormTable bpmFormTable = subTableMap.get(tableName);
                List<Map<String, Object>> dataList = subTable.getDataList();
                for (Map<String, Object> row : dataList) {
                    //获取主键
                    String pk = row.get(subTable.getPkName().toLowerCase()).toString();
                    SqlModel subSqlModel = getInsert(bpmFormTable, row);
                    subSqlModel.setPk(pk);
                    subSqlModel.setFormTable(bpmFormTable);
                    list.add(subSqlModel);
                }
            }

        } else {
            //更新主表数据
            SqlModel sqlModel = getUpdate(mainTable.getIsExternal(), formData);
            if (sqlModel != null) {
                list.add(sqlModel);
                sqlModel.setPk(formData.getPkValue().getValue().toString());
                sqlModel.setFormTable(mainTable);
            }
            //处理子表数据。
            FormHandlerService formHandlerService = AppUtil.getBean(FormHandlerService.class);
            FormRightsService formRightsService = AppUtil.getBean(FormRightsService.class);
            List<JSONObject> subTableShowRights = formRightsService.getSubTableShowRights(procDefId, nodeId, PlatformType.PC);
            for (SubTable subTable : formData.getSubTableList()) {
                String tableName = subTable.getTableName().toLowerCase();
                FormTable table = subTableMap.get(tableName);

                //原来的数据。
                List<Map<String, Object>> subDataList = formHandlerService.getByFk(table, pkValue.getValue().toString(), procDefId, nodeId, true);
                List<Map<String, Object>> curDataList = subTable.getDataList();
                // 当前无数据，需要判断是子表隐藏还是数据的删除
                if (BeanUtils.isEmpty(curDataList)) {
                    boolean isContinue = false;
                    for (JSONObject obj : subTableShowRights) {
                        String tempTableName = obj.getString("tableName");
                        JSONObject showRights = obj.getJSONObject("show");
                        if (tableName.equals(tempTableName) && "true".equalsIgnoreCase(showRights.getString("y"))) {
                            // 如果子表隐藏，则不处理
                            isContinue = true;
                            break;
                        }
                    }
                    if (isContinue) {
                        continue;
                    }
                }
                //更新插入。
                List<SqlModel> updDelList = getUpdDelByList(table, curDataList, subDataList);
                list.addAll(updDelList);
            }
        }
        return list;
    }

    /**
     * 将列表定义转换成Map对象。
     *
     * @param list
     * @return
     */
    private static Map<String, FormTable> convertTableMap(List<FormTable> list) {
        Map<String, FormTable> map = new HashMap<String, FormTable>();
        for (FormTable tb : list) {
            map.put(tb.getTableName().toLowerCase(), tb);
        }
        return map;
    }

    /**
     * 取得插入的数据的sqlmodel对象。
     *
     * @param formTable
     * @param mapData
     * @return
     */
    private static SqlModel getInsert(FormTable formTable, Map<String, Object> mapData) {
        String tableName = formTable.getFactTableName();
        String pkField = formTable.getPkField().toLowerCase();

        StringBuffer fieldNames = new StringBuffer();
        StringBuffer params = new StringBuffer();
        final List<Object> values = new ArrayList<>();

        for (Map.Entry<String, Object> entry : mapData.entrySet()) {
            fieldNames.append(entry.getKey().toUpperCase()).append(",");
            params.append("?,");
            if ("version".equalsIgnoreCase(entry.getKey())) {
                //增加版本号的默认值1
                values.add("1");
            } else {
                values.add(entry.getValue());
            }

        }
        //如果是主表并且主表不是外部表 需要入库创建人 创建时间的值
        if (formTable.getIsMain() == FormTable.IS_MAIN && formTable.getIsExternal() == FormTable.NOT_EXTERNAL) {
            SysUser curUser = (SysUser) ContextUtil.getCurrentUser();
            if (fieldNames.indexOf(FormConstants.FIELD_CREATE_PERSON.toUpperCase()) == -1) {
                fieldNames.append(FormConstants.FIELD_CREATE_PERSON).append(",");
                params.append("?,");
                values.add(curUser.getUserId());

            }
            if (fieldNames.indexOf(FormConstants.FIELD_CREATE_TIME.toUpperCase()) == -1) {
                fieldNames.append(FormConstants.FIELD_CREATE_TIME).append(",");
                params.append("?,");
                values.add(new Date());
            }
        }

        StringBuffer sql = new StringBuffer();
        sql.append(" INSERT INTO ");
        sql.append(tableName);
        sql.append("(");
        sql.append(fieldNames.substring(0, fieldNames.length() - 1));
        sql.append(")");
        sql.append(" VALUES (");
        sql.append(params.substring(0, params.length() - 1));
        sql.append(")");


        SqlModel sqlModel = new SqlModel(sql.toString(), values.toArray(), SqlModel.SQLTYPE_INSERT);

        Object obj = mapData.get(pkField);
        if (BeanUtils.isEmpty(obj)) {
            obj = mapData.get(pkField.toUpperCase());
        }
        sqlModel.setPk(obj.toString());
        sqlModel.setFormTable(formTable);

        return sqlModel;
    }

    public static void valueAdd(FormTable bpmFormTable, List<Object> values, Map.Entry<String, Object> entry) {
        if (StringUtil.isEmpty(entry.getValue())) {
            List<FormField> list = bpmFormTable.getFieldList();
            for (int i = 0; i < list.size(); i++) {
                String fieldName = entry.getKey();
                if (list.get(i).getFieldName().equals(fieldName)) {
                    FormField field = list.get(i);
                    if ("clob".equals(field.getFieldType()) || "blob".equals(field.getFieldType()) || "text".equals(field.getFieldType())) {
                        values.add("");
                        break;
                    } else {
                        values.add(null);
                        break;
                    }
                }
            }
        } else {
            values.add(entry.getValue());
        }
    }

    /**
     * 获取主表的更新的sqlmodel对象。
     * <pre>
     * 只是更新客户端提交的json数据，如果表单中没有提交任何数据则不更新。
     * </pre>
     *
     * @param formData
     * @return
     */
    private static SqlModel getUpdate(int isExternal, FormData formData) {
        PkValue pk = formData.getPkValue();
        String tableName = formData.getFormTable().getFactTableName();
        Map<String, Object> mapData = formData.getMainCommonFields();
        StringBuffer sb = new StringBuffer();

        //判断是否需要做表单版本控制
        boolean exitVer = false;
        if (mapData.containsKey("version")) {
            exitVer = true;
        }
        List<Object> values = new ArrayList<Object>();
        for (Map.Entry<String, Object> entry : mapData.entrySet()) {
            if (!"version".equalsIgnoreCase(entry.getKey())) {
                sb.append(entry.getKey()).append("=?,");
                values.add(entry.getValue());
            }
        }
        if (exitVer) {
            //增加更新版本号+1
            sb.append("version").append("=version+1,");
        }

        //更新 更新人，更新时间的值
        SysUser curUser = (SysUser) ContextUtil.getCurrentUser();

        if (isExternal == FormTable.NOT_EXTERNAL) {
            sb.append("updateby").append("=?,");
            sb.append("updatetime").append("=?,");
            values.add(curUser.getUserId());
            values.add(new Date());
        }
        if (values.isEmpty()) {
            return null;
        }
        StringBuffer sql = new StringBuffer();
        if (sb.length() > 0) {
            // sql
            sql.append(" update ");
            sql.append(tableName);
            sql.append(" set ");
            sql.append(sb.substring(0, sb.length() - 1));
            sql.append(" where ");
            sql.append(pk.getName());
            sql.append("=?");
            if (exitVer) {
                String verVal = mapData.get("version") == null ? "1" : String.valueOf(mapData.get("version"));
                //将版本号添加进更新条件中
                sql.append(" and version=" + verVal);
            }
            values.add(pk.getValue());
        }
        SqlModel sqlModel = new SqlModel(sql.toString(), values.toArray(), SqlModel.SQLTYPE_UPDATE);
        return sqlModel;
    }

    /**
     * 获取更新或者删除的SqlModel列表。
     *
     * @param formTable
     * @param curList
     * @param originList
     * @return
     */
    private static List<SqlModel> getUpdDelByList(FormTable formTable, List<Map<String, Object>> curList, List<Map<String, Object>> originList) {
        String tableName = formTable.getFactTableName();
        String pkField = formTable.getPkField();

        List<SqlModel> rtnList = new ArrayList<>();
        Map<String, Map<String, Object>> curMap = convertMap(pkField, curList);
        Map<String, Map<String, Object>> originMap = convertMap(pkField, originList);
        Set<Map.Entry<String, Map<String, Object>>> curSet = curMap.entrySet();
        //遍历当前数据
        //1.如果当前数据包含原来的数据，那么这个数据进行更新。
        //2.如果当前数据不包含原来的数据，那么添加这个数据。
        for (Iterator<Map.Entry<String, Map<String, Object>>> it = curSet.iterator(); it.hasNext(); ) {
            Map.Entry<String, Map<String, Object>> ent = it.next();
            Map<String, Object> map = ent.getValue();
            //原数据包含当前的数据，则更新。
            if (originMap.containsKey(ent.getKey())) {
                SqlModel updSqlModel = getUpd(tableName, pkField, map, formTable);
                if (updSqlModel != null) {
                    updSqlModel.setFormTable(formTable);
                    rtnList.add(updSqlModel);
                }
            } else {
                SqlModel model = getInsert(formTable, ent.getValue());

                model.setFormTable(formTable);
                rtnList.add(model);
            }
        }
        //遍历原来的数据，当前数据不包含原来的数据，那么需要删除。
        Set<Map.Entry<String, Map<String, Object>>> originSet = originMap.entrySet();
        for (Iterator<Map.Entry<String, Map<String, Object>>> it = originSet.iterator(); it.hasNext(); ) {
            Map.Entry<String, Map<String, Object>> ent = it.next();
            //当前数据不包含之前的数据，则需要删除
            if (!curMap.containsKey(ent.getKey())) {
                String delSql = "delete from " + tableName + " where " + pkField + "=?";
                SqlModel sqlModel = new SqlModel(delSql, new Object[]{ent.getKey()}, SqlModel.SQLTYPE_DEL);
                sqlModel.setPk(ent.getKey());
                sqlModel.setFormTable(formTable);
                rtnList.add(sqlModel);
            }
        }
        return rtnList;
    }

    /**
     * 将列表转化为map对象。
     * <pre>
     * 主键和一行数据进行关联。
     * </pre>
     *
     * @param list
     * @return
     */
    private static Map<String, Map<String, Object>> convertMap(String pkField, List<Map<String, Object>> list) {
        pkField = pkField.toLowerCase();
        Map<String, Map<String, Object>> rtnMap = new HashMap<String, Map<String, Object>>();
        for (Map<String, Object> map : list) {
            if (!map.containsKey(pkField)) {
                continue;
            }
            String value = map.get(pkField).toString();
            rtnMap.put(value, map);
        }
        return rtnMap;
    }

    /**
     * 获取更新的数据model。
     *
     * @param tableName
     * @param mapData
     * @return
     */
    private static SqlModel getUpd(String tableName, String pkField, Map<String, Object> mapData, FormTable formTable) {
        final List<Object> values = new ArrayList<Object>();

        pkField = pkField.toLowerCase();


        String pkValue = mapData.get(pkField).toString();

        StringBuffer set = new StringBuffer();

        for (Map.Entry<String, Object> entry : mapData.entrySet()) {
            if (!pkField.equals(entry.getKey())) {
                set.append(entry.getKey()).append("=?,");
                valueAdd(formTable, values, entry);
            }
        }
        if (values.isEmpty()) {
            return null;
        }
        // sql
        StringBuffer sql = new StringBuffer();

        sql.append(" update ");
        sql.append(tableName);
        sql.append(" set ");
        sql.append(set.substring(0, set.length() - 1));
        sql.append(" where ");
        sql.append(pkField);
        sql.append("=?");
        values.add(pkValue);
        SqlModel sqlModel = new SqlModel(sql.toString(), values.toArray(), SqlModel.SQLTYPE_UPDATE);

        sqlModel.setPk(pkValue);

        return sqlModel;
    }

    /**
     * 将json数据解析为BpmFormData。
     *
     * @param json
     * @param pkValue
     * @return
     * @throws Exception
     */
    public static FormData parseJson(String json, PkValue pkValue, FormTable mainTableDef) throws Exception {
        JSONObject jsonObj = JSONObject.fromObject(json);
        FormData formData = new FormData(mainTableDef);
        if (pkValue == null) {
            pkValue = generatePk(mainTableDef);
        }
        formData.setPkValue(pkValue);
        //处理主表
        handleMain(jsonObj, formData);
        //子表
        handSub(jsonObj, formData);
        //意见
        handOpinion(formData, jsonObj);
        return formData;
    }


    /**
     * 将数据
     * <pre>
     * {
     * 		main: {
     * 			fields:{"字段1":"1","字段2":"2"}
     *        },
     * 		sub: [
     *            {
     * 				tableName: 'TB',
     * 				fields: [
     *                    {"字段1":"1","字段2":"2"},
     *                    {"字段1":"3","字段2":"4"}
     * 				]
     *            },
     *            {
     * 				tableName: 'TB',
     * 				fields: [
     *                    {"字段1":"1","字段2":"2"},
     *                    {"字段1":"3","字段2":"4"}
     * 				]
     *            },
     * 		],
     * 		opinion: [
     *            {name:"意见表单名1",value:"意见"},
     *            {name:"意见表单名1",value:"意见"}
     * 		]
     *    }
     * </pre>
     *
     * @param json
     * @param mainTableDef
     * @return
     * @throws Exception
     */
    public static FormData parseJson(String json, FormTable mainTableDef) throws Exception {
        return parseJson(json, null, mainTableDef);
    }

    /**
     * 直接产生新的主键。
     *
     * @param formTable
     * @return
     * @throws Exception
     */
    public static PkValue generatePk(FormTable formTable) throws Exception {
        Object pkValue = null;
        String pkField = formTable.getPkField().toLowerCase();

        //外部表根据规则创建主键。
        if (formTable.isExtTable()) {
            Short keyType = formTable.getKeyType();
            String keyValue = formTable.getKeyValue();
            pkValue = FormUtil.getKey(keyType, keyValue);
        } else {
            pkValue = UUIDUtils.getUUIDFor32();
        }

        PkValue pk = new PkValue();
        pk.setIsAdd(true);
        pk.setName(pkField);
        pk.setValue(pkValue);
        return pk;
    }

    /**
     * 处理主表的数据
     *
     * @param jsonObj
     * @param formData
     * @throws Exception
     */
    private static void handleMain(JSONObject jsonObj, FormData formData) throws Exception {

        //主表 main
        JSONObject mainTable = jsonObj.getJSONObject("main");
        FormTable mainTableDef = formData.getFormTable();
        List<FormField> mainFields = mainTableDef.getFieldList();
        Map<String, FormField> mainFieldTypeMap = convertFieldToMap(mainFields);
        //主表字段
        JSONObject mainFieldJson = mainTable.getJSONObject("fields");
        //将主表JSON转换成map数据。
        Map<String, Object> mainFiledsData = handleRow(mainTableDef, mainFieldTypeMap, mainFieldJson);
        SysUser curUser = (SysUser) ContextUtil.getCurrentUser();
        //获取租户ID
        String tenantId = ContextUtil.getCurrentUserTenantId();
        //触发新流程防止 两个租户id 将tenantId 修改为 tenantid
        if ("admin".equals(curUser.getAccount())) {
            mainFiledsData.put("tenantid", 0);
        } else {
            mainFiledsData.put("tenantid", tenantId);
        }
        //添加主表数据
        formData.addMainFields(mainFiledsData);

        PkValue pkValue = formData.getPkValue();

        formData.addMainFields(pkValue.getName().toLowerCase(), pkValue.getValue());
        //只有在添加的时候才进行计算。
        if (pkValue.getIsAdd()) {
            //获取需要通过脚本结算的字段。
            List<FormField> mapFormField = getFieldsFromScript(mainFields);
            //通过脚本引擎计算字段。
            Map<String, Object> map = caculateField("", mapFormField, formData.getMainFields(), mainFieldJson);

            formData.addMainFields(map);

            handIdentityField(mainTableDef, formData);
        }

        //设置流程变量
        Map<String, Object> variables = getVariables(mainFieldJson, mainFields);
        formData.setVariables(variables);

    }

    /**
     * 将字段列表转成字段map。
     *
     * @param list
     * @return
     */
    private static Map<String, FormField> convertFieldToMap(List<FormField> list) {
        Map<String, FormField> map = new HashMap<>();
        for (Iterator<FormField> it = list.iterator(); it.hasNext(); ) {
            FormField field = it.next();
            map.put(field.getFieldName().toLowerCase(), field);
        }
        return map;
    }

    /**
     * 将json转换为Map对象。
     *
     * @param bpmFormTable  列前缀。
     * @param fieldTypeMap  字段和类型映射。
     * @param fieldsJsonObj json对象。
     * @return
     */
    private static Map<String, Object> handleRow(FormTable bpmFormTable, Map<String, FormField> fieldTypeMap, JSONObject fieldsJsonObj) {
        boolean isExternal = bpmFormTable.isExtTable();
        int keyType = bpmFormTable.getKeyDataType();
        String colPrefix = "";
        String pkField = bpmFormTable.getPkField();
        Map<String, Object> row = new HashMap<String, Object>();

        //对字段名称进行遍历
        for (Iterator<String> it = fieldsJsonObj.keys(); it.hasNext(); ) {
            String key = it.next();
            Object obj = fieldsJsonObj.get(key);
            String value = "";
            if (obj == JSONNull.getInstance()) {
                value = "";
            } else if (obj instanceof JSONArray || obj instanceof JSONObject) {
                value = obj.toString();
            } else {
                value = obj + "";
            }
            if (pkField.equalsIgnoreCase(key) && StringUtil.isNotEmpty(value)) {
                if (keyType == 0) {
                    row.put(pkField.toLowerCase(), new Long(value));
                } else {
                    row.put(pkField.toLowerCase(), value);
                }

            }

            FormField bpmFormField = fieldTypeMap.get(key.toLowerCase());
            if (bpmFormField == null) {
                continue;
            }
            //转换数据类型
            Object convertValue = convertType(value, bpmFormField);
            String fieldName = key.toLowerCase();
            if (!isExternal && !fieldName.equalsIgnoreCase(TableModel.PK_COLUMN_NAME)) {
                fieldName = (colPrefix + key).toLowerCase();
            }
            row.put(fieldName, convertValue);
        }
        return row;
    }

    /**
     * 转换数据类型。
     *
     * @param strValue
     * @param formField
     * @return
     */
    public static Object convertType(String strValue, FormField formField) {

        String type = formField.getFieldType();
        if (StringUtil.isEmpty(strValue)) {
            return null;
        }
        Object value = strValue;
        if (ColumnModel.COLUMNTYPE_DATE.equals(type)) {
            try {
                value = DateUtils.parseDate(strValue, new String[]{"yyyy-MM-dd HH:mm:ss", "yyyy", "yyyy-MM-dd", "yyyy-MM-dd HH:mm", "HH:mm:ss", "HH:mm", "yyyy-MM-dd HH:mm:ss.SSS"});
            } catch (Exception var3) {
            }
        } else if (ColumnModel.COLUMNTYPE_NUMBER.equals(type)) {
            String json = formField.getCtlProperty();
            JSONObject jsonObj = new JSONObject();
            if (StringUtil.isJson(json)) {
                jsonObj = JSONObject.fromObject(json);
            }
            //替换货币符号
            if (BeanUtils.isNotEmpty(jsonObj.get("coinValue"))) {
                strValue = StringUtil.trimPrefix(strValue, String.valueOf(jsonObj.get("coinValue")));
            }
            //替换千分位
            String isShowComdify = String.valueOf(jsonObj.get("isShowComdify"));
            if ("1".equals(isShowComdify) || "true".equals(isShowComdify)) {
                strValue = strValue.replaceAll(",", "");
            }
            //属于小数类型。
            if (formField.getDecimalLen() > 0) {
                value = Double.parseDouble(strValue);
            }
            //整数型的处理。
            else {
                if (strValue.contains(",")) {
                    strValue = strValue.replaceAll(",","");
                }
                if (strValue.contains(".")) {
                    strValue = StringUtils.substringBefore(strValue, ".");
                }
                if (formField.getIntLen() <= 10) {
                    value = Integer.parseInt(strValue);
                } else {
                    value = Long.parseLong(strValue);
                }
            }
        }
        return value;
    }

    /**
     * 取得值需要结算的字段。
     *
     * @param list
     * @return
     */
    private static List<FormField> getFieldsFromScript(List<FormField> list) {
        List<FormField> map = new ArrayList<>();
        for (FormField field : list) {
            //通过后台运算
            if (field.getValueFrom() == 2) {
                map.add(field);
            }
        }
        return map;
    }

    /**
     * 计算值从脚本的来的值。
     *
     * @param colPrefix 列前缀。
     * @param fields    子表字段。
     * @param rowData   子表的一行数据。
     * @return
     */
    private static Map<String, Object> caculateField(String colPrefix, List<FormField> fields, Map<String, Object> rowData, JSONObject mainFieldJson) {

        Map<String, Object> result = new HashMap<String, Object>();
        for (FormField field : fields) {
            String fieldName = field.getFieldName().toLowerCase();
            //实际字段名称
            String name = colPrefix + field.getFieldName();
            //获取字段脚本。
            String script = field.getScript();
            Object value = FormUtil.calcuteField(script, rowData);
            //脚本不显示 ，用脚本计算的值覆盖新值
            if (mainFieldJson != null) {
                mainFieldJson.put(fieldName, value);
            }
            result.put(name.toLowerCase(), value);
        }
        return result;
    }

    /**
     * 处理后置的流水号。
     */
    private static void handIdentityField(FormTable mainTableDef, FormData formData) {
        List<FormField> list = mainTableDef.getFieldList();
        IdentityService identityService = AppUtil.getBean(IdentityService.class);
        String colPrefix = "";
        for (FormField field : list) {
            // 值来源为流水号。
            if (field.getValueFrom() != FormField.VALUE_FROM_IDENTITY) {
                continue;
            }
            //处理启动流程时是否显示流水号的数据，判断依据来源于设计字段时，是否勾选了 启动时显示   isShowidentity=1  显示在启动页面, 为0则显示
            String prop = field.getCtlProperty();
            if (StringUtil.isEmpty(prop)) {
                continue;
            }
            JSONObject jsonObject = JSONObject.fromObject(prop);
            if (jsonObject.containsKey("isShowidentity")) {
                String isShowidentity = jsonObject.getString("isShowidentity");
                if ("0".equals(isShowidentity)) {
                    Identity identity = identityService.getByIdentityName(field.getIdentity());
                    String idNo = identityService.nextId(identity.getAlias());
                    String fieldName = field.getFieldName();
                    String columnName = colPrefix + fieldName;
                    formData.addMainFields(columnName.toLowerCase(), idNo);
                }
            }
        }
    }

    /**
     * 获取流程变量。
     *
     * @param jsonObject
     * @param list
     * @return
     */
    private static Map<String, Object> getVariables(JSONObject jsonObject, List<FormField> list) {
        Map<String, Object> map = new HashMap<String, Object>();
        Map<String, FormField> fieldsMap = convertFieldToMap(list);
        for (Iterator it = jsonObject.keys(); it.hasNext(); ) {
            String key = (String) it.next();
            String lowerKey = key.toLowerCase();
            FormField field = fieldsMap.get(lowerKey);
            if (field != null && field.getIsFlowVar() == 1) {
                Object value = jsonObject.get(key);
                if (value != JSONNull.getInstance()) {
                    Object obj = convertType(value.toString(), field);
                    map.put(key, obj);
                }
            }
        }
        return map;
    }

    /**
     * 处理子表数据
     *
     * @param jsonObj
     * @param formData
     * @throws Exception
     */
    private static void handSub(JSONObject jsonObj, FormData formData) throws Exception {
        FormTable mainTable = formData.getFormTable();
        List<FormTable> listTable = mainTable.getSubTableList();
        //将表名消息并作为键和表对象进行关联。
        Map<String, FormTable> formTableMap = convertTableMap(listTable);

        boolean isExternal = mainTable.isExtTable();

        String colPrefix = "";

        //子表
        JSONArray arySub = jsonObj.getJSONArray("sub");
        //子表
        for (int i = 0; i < arySub.size(); i++) {
            SubTable subTable = new SubTable();
            JSONObject subTableObj = arySub.getJSONObject(i);
            String tableName = subTableObj.getString("tableName").toLowerCase();
            //根据子表名称获取子表对象
            FormTable subFormTable = formTableMap.get(tableName);
            //获取子表的列元数据。
            List<FormField> subTableFields = subFormTable.getFieldList();
            //将子表的字段名称作为键，字段对象作为值放到map对象当中。
            Map<String, FormField> subTableTypeMap = convertFieldToMap(subTableFields);
            //获取需要计算的脚本数据。
            List<FormField> scriptFields = getFieldsFromScript(subTableFields);
            List<FormField> flowFields = getFieldsFromFlowNum(subTableFields);
            //设置子表名称
            subTable.setTableName(tableName);
            //设置子表的主键和外键名称。
            if (isExternal) {
                String pk = subFormTable.getPkField();
                subTable.setPkName(pk);
                subTable.setFkName(subFormTable.getRelation());
            } else {
                subTable.setPkName(TableModel.PK_COLUMN_NAME);
                subTable.setFkName(TableModel.FK_COLUMN_NAME);
            }
            JSONArray arySubFields = subTableObj.getJSONArray("fields");
            for (int j = 0; j < arySubFields.size(); j++) {
                JSONObject subFieldObj = arySubFields.getJSONObject(j);
                Map<String, Object> subRow = handleRow(subFormTable, subTableTypeMap, subFieldObj);
                //计算脚本字段。
                Map<String, Object> map = caculateField(colPrefix, scriptFields, subRow, null);
                Map<String, Object> flowmap = caculateFlowField(colPrefix, flowFields, subRow, null);

                subRow.putAll(map);
                subRow.putAll(flowmap);
                //处理主键数据
                handFkRow(subFormTable, subRow, formData.getPkValue());
                //处理需要计算的数据。
                subTable.addRow(subRow);
            }
            formData.addSubTable(subTable);
        }
    }

    /**
     * 取得需要设置流水号的字段。
     *
     * @param list
     * @return
     */
    private static List<FormField> getFieldsFromFlowNum(List<FormField> list) {
        List<FormField> map = new ArrayList<>();
        for (FormField field : list) {
            //通过后台运算
            if (field.getValueFrom() == 3) {
                map.add(field);
            }
        }
        return map;
    }

    /**
     * 计算从流水号来的值。
     *
     * @param colPrefix 列前缀。
     * @param fields    子表字段。
     * @param rowData   子表的一行数据。
     * @return
     */
    private static Map<String, Object> caculateFlowField(String colPrefix, List<FormField> fields, Map<String, Object> rowData, JSONObject mainFieldJson) {
        IdentityService identityService = AppUtil.getBean(IdentityService.class);
        Map<String, Object> result = new HashMap<String, Object>();
        for (FormField field : fields) {
            //实际字段名称
            String name = colPrefix + field.getFieldName();
            if (rowData.get(name.toLowerCase()) == null) {
                Identity identity = identityService.getByIdentityName(field.getIdentity());
                Object value = identityService.nextId(identity.getAlias());
                result.put(name.toLowerCase(), value);
            }
        }
        return result;
    }

    /**
     * 处理子表行数据的主键和外键。
     * <pre>
     * 添加子表的主键和外键。
     * </pre>
     *
     * @param bpmFormTable 子表定义。
     * @param rowData      子表一行数据。
     * @param pkValue      主键数据。
     * @throws Exception
     */
    public static void handFkRow(FormTable bpmFormTable, Map<String, Object> rowData, PkValue pkValue) throws Exception {
        boolean isExternal = bpmFormTable.isExtTable();
        //外部表数据
        if (isExternal) {
            String pkField = bpmFormTable.getPkField().toLowerCase();
            if (!rowData.containsKey(pkField)) {
                PkValue pk = generatePk(bpmFormTable);
                rowData.put(pk.getName(), pk.getValue());
            } else {
                Object obj = rowData.get(pkField);
                if (obj == null || "".equals(obj.toString().trim())) {
                    PkValue pk = generatePk(bpmFormTable);
                    rowData.put(pk.getName(), pk.getValue());
                }
            }
            String fk = bpmFormTable.getRelation();
            rowData.put(fk, pkValue.getValue());
        }
        //本地表数据
        else {
            String pkField = bpmFormTable.getPkField().toLowerCase();
            //没有包含主键则添加一个。
            if (!rowData.containsKey(pkField)) {
                String pk = UUIDUtils.getUUIDFor32();
                rowData.put(TableModel.PK_COLUMN_NAME.toLowerCase(), pk);
            }

            rowData.put(TableModel.FK_COLUMN_NAME.toLowerCase(), pkValue.getValue());
        }

    }

    /**
     * 处理意见数据。
     *
     * @param formData
     * @param jsonObj
     */
    private static void handOpinion(FormData formData, JSONObject jsonObj) {
        //意见
        JSONArray aryOpinion = jsonObj.getJSONArray("opinion");
        //意见 opinion
        for (int i = 0; i < aryOpinion.size(); i++) {
            JSONObject opinion = aryOpinion.getJSONObject(i);
            String formName = opinion.getString("name");
            String value = opinion.getString("value");
            formData.addOpinion(formName, value);
        }
    }
}
